﻿using Autofac;
using Lanbt.Core.Service.SqlService;
using Lanbt.Core.Utility;
using Lanbt.Core.Web.Filter;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
using Quartz;
using SqlSugar;
using System.Reflection;

namespace Lanbt.Core.Web.ServiceExtent
{
    public static class ServiceSetup
    {
        /// <summary>
        /// 烂笔头服务注入到容器
        /// </summary>
        /// <param name="services"></param>
        public static void AddLanbtServer(this IServiceCollection services)
        {
            //添加服务到容器
            services.AddControllersWithViews(options =>
            {
                //全局异常处理
                options.Filters.Add(typeof(GlobalExceptionFilter));

                //全局模型验证
                options.Filters.Add(typeof(GlobalValidateFilter));

                //抑制非空引用类型所需的隐含属性
                options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;

            }).AddNewtonsoftJson(options =>
            {
                // 返回数据首字母小写，DefaultContractResolver 是不小写
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

            //SQLSugar 服务注册
            services.AppSqlsugarSetup();

            //自动映射配置
            services.AddAutoMapper(Assembly.Load("Lanbt.Core.Service"));
            //添加Http上下访问器
            services.AddHttpContextAccessor();
            //添加存储缓存
            services.AddMemoryCache();
            //添加Http服务
            services.AddHttpClient();
            //添加烂笔头IOC容器
            services.AddLanbtICO(typeof(ServiceBase));

            #region SwaggerUI

            //注册Swagger
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo()
                {
                    Version = "v1",
                    Title = "lanbt.core",
                    Description = "烂笔头Swagger管理接口"
                });
                //引入接口注释
                options.IncludeXmlComments("Lanbt.Core.Web.xml",true);
                options.IncludeXmlComments("Lanbt.Core.Entity.xml");
                options.DocumentFilter<SwaggerTagDesc>();

                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "直接在输入框中输入认证信息，不需要在开头添加Bearer",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    Scheme = "Bearer"
                });

                options.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                  {
                    new OpenApiSecurityScheme
                    {
                      Reference = new OpenApiReference
                      {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                      },Scheme = "oauth2",Name = "Bearer",In = ParameterLocation.Header,
                    },new List<string>()
                  }
                });
            });

            #endregion SwaggerUI

            #region JWT

            //JWT服务注册
            //services.AddAuthentication(options =>
            //{
            //    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            //})
            //.AddJwtBearer(options =>
            //{
            //    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            //    {
            //        ValidateIssuer = true,//是否验证Issuer
            //        ValidIssuer = GlobalContext.SystemConfig.Issuer,//发行人Issuer
            //        ValidateAudience = true,//是否验证Audience
            //        ValidAudience = GlobalContext.SystemConfig.Audience,//订阅人Audience
            //        ValidateIssuerSigningKey = true,//是否验证SecurityKey
            //        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(GlobalContext.SystemConfig.SecreKey)),//SecurityKey
            //        ValidateLifetime = true,//是否验证失效时间
            //        ClockSkew = TimeSpan.FromSeconds(30),//过期时间容错值，解决服务器端时间不同步问题（秒）
            //        RequireExpirationTime = true,
            //    };
            //});

            #endregion JWT

            #region Quartz

            //添加Quartz服务
            services.AddQuartz(quartzConfiguartor =>
            {
                //设置默认调度名称
                quartzConfiguartor.SchedulerName = "LANBT_SCHEDULER";

                quartzConfiguartor.UsePersistentStore(x =>
                {
                    //使用属性
                    x.UseProperties = true;
                    //使用集群
                    //x.UseClustering();
                    //配置SqlServer数据库
                    x.UseSqlServer(sql =>
                    {
                        sql.TablePrefix = GlobalContext.SystemConfig.QuartzTablePrefix;
                        sql.ConnectionString = GlobalContext.SystemConfig.SqlConnection;
                    });
                    //使用JSON序列化
                    x.UseJsonSerializer();

                });

                //使用默认线程池
                quartzConfiguartor.UseDefaultThreadPool(x =>
                {
                    //设置最大并发
                    x.MaxConcurrency = 25;
                });
            });

            //添加Quartz托管服务
            services.AddQuartzHostedService(opt =>
            {
                //等待任务完成
                opt.WaitForJobsToComplete = true;
            });

            #endregion Quartz

            GlobalContext.Services = services;
        }

        /// <summary>
        /// 添加 SqlSugar 到容器
        /// </summary>
        /// <param name="service"></param>
        private static void AppSqlsugarSetup(this IServiceCollection service)
        {
            var sqlSugar = new SqlSugarScope(
                new SqlSugar.ConnectionConfig
                {
                    DbType = DbType.SqlServer,
                    ConnectionString = GlobalContext.SystemConfig.SqlConnection,
                    IsAutoCloseConnection = true,
                    ConfigureExternalServices = new ConfigureExternalServices
                    {
                        //注意:  这儿AOP设置不能少
                        EntityService = (c, p) =>
                        {
                            // int?  decimal?这种 isnullable=true 不支持string
                            if (c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                            {
                                p.IsNullable = true;
                            }

                            //高版C#写法 支持string?和string  
                            if (new NullabilityInfoContext().Create(c).WriteState is NullabilityState.Nullable)
                            {
                                p.IsNullable = true;
                            }
                        }
                    }
                },
                db =>
                {
                    db.Aop.OnLogExecuting = (sql, pars) =>
                    {
                        //Console.WriteLine("sql语句：" + sql);
                    };
                });

            service.AddSingleton<ISqlSugarClient>(sqlSugar);
        }

        /// <summary>
        /// 烂笔头IOC容器
        /// </summary>
        /// <remarks>参数：type；继承type的所有类都单例加入ICO容器</remarks>
        /// <param name="service"></param>
        /// <param name="type">继承的类</param>
        private static void AddLanbtICO(this IServiceCollection service,Type type)
        {
            var repositorys = Assembly.Load("Lanbt.Core.Repository").GetTypes()
                .Where(x => x.IsClass && !x.IsAbstract)
                .Where(x => x.Name.EndsWith("Repository"));
            foreach (var item in repositorys)
            {
                var @interface = item.GetInterfaces().Where(x => x.Name.EndsWith(item.Name)).FirstOrDefault();
                if(@interface != null)
                {
                    service.AddSingleton(@interface, item);
                }
            }

            var services = Assembly.Load("Lanbt.Core.Service").GetTypes()
                .Where(x => x.IsClass && !x.IsAbstract)
                .Where(x => x.Name.EndsWith("Service"));
            foreach (var item in services)
            {
                var @interface = item.GetInterfaces().Where(x => x.Name.EndsWith(item.Name)).FirstOrDefault();
                if (@interface != null)
                {
                    service.AddSingleton(@interface, item);
                }
            }

            //var assemblys = type.Assembly.GetTypes()
            //    .Where(x=> type.IsAssignableFrom(x))//继承于哪个类
            //    .Where(x=>x.IsClass && !x.IsAbstract)
            //    .Where(x=>x.GetType() != type);

            //foreach (var item in assemblys)
            //{
            //    var @interface = item.GetInterfaces().Where(x=>x.Name.EndsWith(item.Name)).FirstOrDefault();
            //    if(@interface != null)
            //    {
            //        service.AddSingleton(@interface, item);
            //    }
            //    else
            //    {
            //        service.AddSingleton(item);
            //    }
            //}
            
        }
    }
}
